package com.reactim.message.metrics;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Protobuf性能监控指标
 */
@Slf4j
@Component
public class ProtobufPerformanceMetrics {
    
    private final MeterRegistry meterRegistry;
    
    // 转换性能指标
    private final Timer protoToEntityTimer;
    private final Timer entityToProtoTimer;
    private final Counter conversionErrorCounter;
    
    // 压缩性能指标
    private final Timer compressionTimer;
    private final Timer decompressionTimer;
    private final Counter compressionCounter;
    private final Counter decompressionCounter;
    
    // 消息大小统计
    private final AtomicLong totalOriginalBytes = new AtomicLong(0);
    private final AtomicLong totalCompressedBytes = new AtomicLong(0);
    private final AtomicLong messageCount = new AtomicLong(0);
    
    public ProtobufPerformanceMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 初始化转换指标
        this.protoToEntityTimer = Timer.builder("protobuf.conversion.proto_to_entity")
                .description("Protobuf转实体类的耗时")
                .register(meterRegistry);
        
        this.entityToProtoTimer = Timer.builder("protobuf.conversion.entity_to_proto")
                .description("实体类转Protobuf的耗时")
                .register(meterRegistry);
        
        this.conversionErrorCounter = Counter.builder("protobuf.conversion.errors")
                .description("Protobuf转换错误次数")
                .register(meterRegistry);
        
        // 初始化压缩指标
        this.compressionTimer = Timer.builder("protobuf.compression.time")
                .description("消息压缩耗时")
                .register(meterRegistry);
        
        this.decompressionTimer = Timer.builder("protobuf.decompression.time")
                .description("消息解压缩耗时")
                .register(meterRegistry);
        
        this.compressionCounter = Counter.builder("protobuf.compression.count")
                .description("消息压缩次数")
                .register(meterRegistry);
        
        this.decompressionCounter = Counter.builder("protobuf.decompression.count")
                .description("消息解压缩次数")
                .register(meterRegistry);
        
        // 注册自定义指标
        meterRegistry.gauge("protobuf.compression.ratio", this, ProtobufPerformanceMetrics::getCompressionRatio);
        meterRegistry.gauge("protobuf.average.original_size", this, ProtobufPerformanceMetrics::getAverageOriginalSize);
        meterRegistry.gauge("protobuf.average.compressed_size", this, ProtobufPerformanceMetrics::getAverageCompressedSize);
    }
    
    /**
     * 记录Proto转实体的性能
     */
    public <T> T recordProtoToEntity(String operation, java.util.function.Supplier<T> supplier) {
        try {
            return protoToEntityTimer.recordCallable(() -> {
                try {
                    T result = supplier.get();
                    log.debug("Proto转实体完成: operation={}", operation);
                    return result;
                } catch (Exception e) {
                    conversionErrorCounter.increment();
                    log.error("Proto转实体失败: operation={}", operation, e);
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录实体转Proto的性能
     */
    public <T> T recordEntityToProto(String operation, java.util.function.Supplier<T> supplier) {
        try {
            return entityToProtoTimer.recordCallable(() -> {
                try {
                    T result = supplier.get();
                    log.debug("实体转Proto完成: operation={}", operation);
                    return result;
                } catch (Exception e) {
                    conversionErrorCounter.increment();
                    log.error("实体转Proto失败: operation={}", operation, e);
                    throw new RuntimeException(e);
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录压缩性能
     */
    public <T> T recordCompression(java.util.function.Supplier<T> supplier) {
        try {
            return compressionTimer.recordCallable(() -> {
                compressionCounter.increment();
                return supplier.get();
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录解压缩性能
     */
    public <T> T recordDecompression(java.util.function.Supplier<T> supplier) {
        try {
            return decompressionTimer.recordCallable(() -> {
                decompressionCounter.increment();
                return supplier.get();
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 记录消息大小统计
     */
    public void recordMessageSize(int originalSize, int compressedSize) {
        totalOriginalBytes.addAndGet(originalSize);
        totalCompressedBytes.addAndGet(compressedSize);
        messageCount.incrementAndGet();
        
        log.debug("记录消息大小: 原始={}字节, 压缩后={}字节", originalSize, compressedSize);
    }
    
    /**
     * 获取压缩比
     */
    public double getCompressionRatio() {
        long original = totalOriginalBytes.get();
        long compressed = totalCompressedBytes.get();
        
        if (original == 0) {
            return 1.0;
        }
        
        return (double) compressed / original;
    }
    
    /**
     * 获取平均原始消息大小
     */
    public double getAverageOriginalSize() {
        long count = messageCount.get();
        if (count == 0) {
            return 0.0;
        }
        return (double) totalOriginalBytes.get() / count;
    }
    
    /**
     * 获取平均压缩后消息大小
     */
    public double getAverageCompressedSize() {
        long count = messageCount.get();
        if (count == 0) {
            return 0.0;
        }
        return (double) totalCompressedBytes.get() / count;
    }
    
    /**
     * 获取性能统计报告
     */
    public PerformanceReport getPerformanceReport() {
        return PerformanceReport.builder()
                .totalMessages(messageCount.get())
                .totalOriginalBytes(totalOriginalBytes.get())
                .totalCompressedBytes(totalCompressedBytes.get())
                .compressionRatio(getCompressionRatio())
                .averageOriginalSize(getAverageOriginalSize())
                .averageCompressedSize(getAverageCompressedSize())
                .compressionCount(compressionCounter.count())
                .decompressionCount(decompressionCounter.count())
                .averageCompressionTime(compressionTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageDecompressionTime(decompressionTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageProtoToEntityTime(protoToEntityTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .averageEntityToProtoTime(entityToProtoTimer.mean(java.util.concurrent.TimeUnit.MILLISECONDS))
                .conversionErrors(conversionErrorCounter.count())
                .build();
    }
    
    /**
     * 重置统计数据
     */
    public void reset() {
        totalOriginalBytes.set(0);
        totalCompressedBytes.set(0);
        messageCount.set(0);
        log.info("性能监控统计数据已重置");
    }
    
    /**
     * 性能报告数据结构
     */
    @lombok.Data
    @lombok.Builder
    public static class PerformanceReport {
        private long totalMessages;
        private long totalOriginalBytes;
        private long totalCompressedBytes;
        private double compressionRatio;
        private double averageOriginalSize;
        private double averageCompressedSize;
        private double compressionCount;
        private double decompressionCount;
        private double averageCompressionTime;
        private double averageDecompressionTime;
        private double averageProtoToEntityTime;
        private double averageEntityToProtoTime;
        private double conversionErrors;
        
        @Override
        public String toString() {
            return String.format(
                "ProtobufPerformanceReport{\n" +
                "  总消息数: %d\n" +
                "  总原始字节数: %d\n" +
                "  总压缩字节数: %d\n" +
                "  压缩比: %.2f%%\n" +
                "  平均原始大小: %.2f字节\n" +
                "  平均压缩大小: %.2f字节\n" +
                "  压缩次数: %.0f\n" +
                "  解压缩次数: %.0f\n" +
                "  平均压缩耗时: %.2fms\n" +
                "  平均解压缩耗时: %.2fms\n" +
                "  平均Proto转实体耗时: %.2fms\n" +
                "  平均实体转Proto耗时: %.2fms\n" +
                "  转换错误次数: %.0f\n" +
                "}",
                totalMessages, totalOriginalBytes, totalCompressedBytes,
                compressionRatio * 100, averageOriginalSize, averageCompressedSize,
                compressionCount, decompressionCount,
                averageCompressionTime, averageDecompressionTime,
                averageProtoToEntityTime, averageEntityToProtoTime,
                conversionErrors
            );
        }
    }
}